package com.mini.grpc.client;

import com.mini.grpc.common.MethodDescriptor;

/**
 * AbstractStub是客户端存根的抽象基类。
 *
 * @param <S> 存根类型，用于方法链式调用
 */
public abstract class AbstractStub<S extends AbstractStub<S>> {
    
    protected final MiniGrpcChannel channel;
    protected final CallOptions callOptions;
    
    /**
     * 创建一个新的AbstractStub
     *
     * @param channel 通道
     * @param callOptions 调用选项
     */
    protected AbstractStub(MiniGrpcChannel channel, CallOptions callOptions) {
        this.channel = channel;
        this.callOptions = callOptions;
    }
    
    /**
     * 返回this的类型转换，用于方法链式调用
     *
     * @return this的类型转换
     */
    protected abstract S thisT();
    
    /**
     * 创建一个带有新通道的存根
     *
     * @param channel 新通道
     * @return 新存根
     */
    protected abstract S build(MiniGrpcChannel channel, CallOptions callOptions);
    
    /**
     * 创建一个带有新调用选项的存根
     *
     * @param callOptions 新调用选项
     * @return 新存根
     */
    public S withOptions(CallOptions callOptions) {
        return build(channel, callOptions);
    }
    
    /**
     * 创建一个带有拦截器的存根
     *
     * @param interceptors 拦截器数组
     * @return 新存根
     */
    public S withInterceptors(ClientInterceptor... interceptors) {
        return withOptions(callOptions.withInterceptors(interceptors));
    }
    
    /**
     * 创建一个带有调用选项的存根
     *
     * @param option 选项键
     * @param value 选项值
     * @param <T> 选项值类型
     * @return 新存根
     */
    public <T> S withOption(CallOptions.CallOption<T> option, T value) {
        return withOptions(callOptions.withOption(option, value));
    }
    
    /**
     * 创建一个带有截止时间的存根
     *
     * @param duration 持续时间
     * @param unit 时间单位
     * @return 新存根
     */
    public S withDeadlineAfter(long duration, java.util.concurrent.TimeUnit unit) {
        return withOptions(callOptions.withDeadlineAfter(duration, unit));
    }
    
    /**
     * 创建一个新的调用
     *
     * @param method 方法描述符
     * @param <ReqT> 请求类型
     * @param <RespT> 响应类型
     * @return 客户端调用
     */
    protected <ReqT, RespT> ClientCall<ReqT, RespT> newCall(MethodDescriptor<ReqT, RespT> method) {
        System.out.println("=== AbstractStub.newCall called for method: " + method.getFullMethodName() + " ===");
        System.out.println("Channel: " + channel.getClass().getName());
        System.out.println("CallOptions: " + callOptions);
        
        ClientCall<ReqT, RespT> call = channel.newCall(method, callOptions);
        System.out.println("Created call: " + call.getClass().getName());
        
        return call;
    }
} 